package com.stox.client.ui.javafx.chartingy.model.plot;

import java.util.ArrayList;
import java.util.List;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;

import com.stox.client.ui.javafx.chartingy.model.axis.DateAxis;
import com.stox.client.ui.javafx.chartingy.model.chart.Chart;
import com.stox.client.ui.javafx.chartingy.model.enumeration.Overlay;
import com.stox.client.ui.javafx.chartingy.model.node.VolumeDataNode;
import com.stox.client.ui.javafx.chartingy.view.ChartingView;
import com.stox.shared.i18n.MessageSource;
import com.stox.shared.model.Bar;
import com.stox.shared.model.Scrip;

public class VolumePlot extends Plot<Scrip, Bar> {

	private final ChartingView chartingView;

	public VolumePlot(final ChartingView chartingView) {
		this.chartingView = chartingView;
		overlayProperty().addListener(new ChangeListener<Overlay>() {
			@Override
			public void changed(final ObservableValue<? extends Overlay> observable, final Overlay oldValue, final Overlay newValue) {
				updateChart();
			}
		});
		chartingView.getPrimaryChart().getPlots().add(this); // TODO should come from preferences
		displayNameProperty().set(MessageSource.get("Volume"));
		setIndex(Integer.MIN_VALUE);
		getPlotInfoPanel().getRemoveButton().setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(final ActionEvent event) {
				setOverlay(Overlay.VOLUME);
			}
		});
	}


	public void updateChart() {
		/**
		 * First remove this plot from parent chart's plots property [This happens when parent is PrimaryChart]
		 */
		if (null != getChart()) {
			getChart().getPlots().remove(this);
		}

		/**
		 * If this plot is a primary plot, it would be still there in chart, thus remove it as primary plot from parent
		 * chart [This happens when volume is being displayed independently]
		 */
		if ((null != getChart()) && equals(getChart().getPrimaryPlot())) {
			getChart().setPrimaryPlot(null);
		}

		/**
		 * Null overlay means independent display for volume plot
		 */
		if (null == getOverlay()) {
			final Chart<Scrip, Bar> chart = new Chart<>(chartingView);
			chartingView.getCharts().add(chart);
			chart.setPrimaryPlot(this);
			super.updateAxisBounds();
		} else {
			switch (getOverlay()) {
				case PRICE:
					chartingView.getPrimaryChart().getPlots().add(this);
					break;
				/**
				 * VOLUME overlay for volume plot means it is to be hidden
				 */
				case VOLUME:
					break;
				default:
					break;
			}
		}
	}

	@Override
	public void updateAxisBounds() {
		double max = Double.MIN_VALUE;
		double min = Double.MAX_VALUE;
		final DateAxis dateAxis = primaryChart().getDateAxis();
		final int lowerBoundIndex = dateAxis.getLowerBoundIndex();
		final int upperBoundIndex = dateAxis.getUpperBoundIndex();
		for (int index = lowerBoundIndex; index >= upperBoundIndex; index--) {
			if (index < dataProperty().getSize()) {
				final Data<Scrip, Bar> data = dataProperty().get(index);
				max = Math.max(max, data.getMax());
				min = Math.min(min, data.getMin());
			}
		}
		setMin(min);
		setMax(max);
		if (isPrimary()) {
			final Chart<Scrip, Bar> chart = getChart();
			chart.setMin(Math.min(chart.getMin(), min));
			chart.setMax(Math.max(chart.getMax(), max));
		}
	}

	@Override
	public void updateDataNodes(final List<? extends Data<Scrip, Bar>> datas) {
		for (final Data<Scrip, Bar> data : datas) {
			data.setDataNode(new VolumeDataNode(data));
		}
	}

	@Override
	public void load() {
		if (null != primaryPlot()) {
			final int size = primaryPlot().getBars().size();
			final List<Data<Scrip, Bar>> datas = new ArrayList<>(size);
			previousBackingDataMax = backingDataMax;
			previousBackingDataMin = backingDataMin;
			backingDataMax = Double.MIN_VALUE;
			backingDataMin = Double.MAX_VALUE;
			for (int index = 0; index < size; index++) {
				final Bar bar = primaryPlot().getBars().get(index);
				final double volume = bar.getVolume();
				backingDataMax = Math.max(backingDataMax, volume);
				backingDataMin = Math.min(backingDataMin, volume);
				datas.add(new Data<Scrip, Bar>(bar.getDate().getTime(), volume, volume, volume, bar, this, index));
			}
			dataProperty().setAll(datas);
		}
	}

}
